package com.cdy.demo.agent;

import java.io.IOException;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
import java.lang.instrument.UnmodifiableClassException;
import java.security.ProtectionDomain;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


public class Agent {

    public static CommandLineContext commandLineContext = new CommandLineContext();

    private static List<Command> commandList = new ArrayList<>();

    private static ExecutorService agentThread = Executors.newSingleThreadExecutor();


    static {
        commandList.add(new ClassFileCommand());
        commandList.add(new WatchCommand());
    }

    public static void agentmain(String agentArgs, Instrumentation inst) {
        System.out.println("Agent Main called");
        System.out.println("agentArgs : " + agentArgs);
        System.out.println("Agent classLoader:" + Agent.class.getClassLoader());
        inst.addTransformer(new ClassFileTransformer() {
            @Override
            public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
                className = className.replace("/", ".");
                System.out.println("transform loader :"+loader);
                System.out.println("transform className :"+className);
                CommandContext commandContext = new CommandContext();
                commandContext.setClassfileBuffer(classfileBuffer);
                commandContext.setClassName(className);
                commandContext.setLoader(loader);
                commandContext.setProtectionDomain(protectionDomain);
                for (Command command : commandList) {
                    if (command.meet()) {
                        return command.transform(commandContext);
                    }
                }
                return null;
            }
        }, true);

        System.out.println("agentmain:"+Thread.currentThread().getContextClassLoader());
        System.out.println("agentmain:"+Thread.currentThread().getName());
        agentThread.submit(() -> {
            System.out.println(Thread.currentThread().getName() + "-park");
            commandLineContext.setCommandType(CommandTypeConstant.watch);
            commandLineContext.setCommandClass("com.cdy.demo.Controller");
            commandLineContext.setCommandMethod("hello");
            retransformClasses(inst);
            try {
                System.in.read();
            } catch (IOException e) {
                e.printStackTrace();
            }
        });
        System.out.println("agentMain end;");
    }

    public static void retransformClasses(Instrumentation inst) {
        Class<?> clazz = null;
        try {
            clazz = Class.forName(commandLineContext.getCommandClass());
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        try {
            inst.retransformClasses(clazz);
        } catch (UnmodifiableClassException e) {
            e.printStackTrace();
        }
    }


}